from .models import OrderGoods, OrderInfo
from rest_framework import serializers
from datetime import datetime
from django_redis import get_redis_connection
from goods.models import SKU
from django.db import transaction


class SaveOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderInfo
        fields = ('order_id', 'address', 'pay_method')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            "address": {
                "write_only": True,
                "required": True
            },
            "pay_method": {
                "write_only": True,
                "required": True
            }
        }

    # 重写create 添加对数据库的操作
    def create(self, validated_data):
        """
        思路:
            1. 创建基本订单对象
            2. 从redis查询购物车商品信息
            3. 遍历商品对象列表
                3.1 判断库存是否足够,不足则抛异常
                3.2 修改goods 销量 库存
                3.3 修改SPU总库存
                3.4 创建OrderGoods对象
                3.5 计算总金额 总数量
            4. 修改总金额 总数量
            5. 删除redis 中购物车的信息
            6. 实现事务 --> mysql
        """
        # 开启事务
        with transaction.atomic():
            # 创建保存点
            sid = transaction.savepoint()
            user = self.context["request"].user
            # 创建基本订单对象
            order = OrderInfo.objects.create(order_id=datetime.now().strftime("%Y%m%d%H%M%S") + "%09d" % user.id,
                                             user=user, address=validated_data["address"], freight=10,
                                             pay_method=validated_data["pay_method"],
                                             status=2 if validated_data["pay_method"] == 1 else 1,
                                             total_count=0,
                                             total_amount=0)
            # 连接redis数据库
            redis_cli = get_redis_connection("cart")
            cart_dict = redis_cli.hgetall("cart%d" % user.id)
            # bytes --> int
            cart_dict = {int(sku_id): int(count) for sku_id, count in cart_dict.items()}
            cart_selected = redis_cli.smembers("cart_selected%d" % user.id)
            cart_selected = [int(sku_id) for sku_id in cart_selected]
            total_count = 0
            total_amount = 0
            for sku_id in cart_selected:
                while True:
                    # 查询对象
                    sku = SKU.objects.get(pk=sku_id)
                    count = cart_dict[sku.id]
                    if count > sku.stock:
                        # 库存不足时回滚
                        transaction.savepoint_rollback(sid)
                        raise serializers.ValidationError("库存不足")
                    stock_old = sku.stock
                    sales_old = sku.sales
                    import time
                    time.sleep(5)
                    # 判断:库存是否为之前的值
                    result = SKU.objects.filter(stock=stock_old, pk=sku.id).update(stock=stock_old - count,
                                                                               sales=sales_old + count)
                    # 语句返回受影响的行数
                    print(result)
                    if result == 0:
                        # 还需判断是否库存足够
                        continue

                    # 修改SPU的总库存
                    goods = sku.goods
                    goods.sales += count
                    goods.save()
                    # 创建OrderGoods对象
                    ordergood = OrderGoods.objects.create(order=order, sku=sku, count=count, price=sku.price)
                    # 计算总金额 总数量
                    total_count += count
                    total_amount += sku.price * count
                    break
            order.total_count = total_count
            order.total_amount = total_amount
            order.save()
            # 提交事务
            transaction.savepoint_commit(sid)

        # 管道命令 删除redis中的购物车信息
        redis_pl = redis_cli.pipeline()
        redis_pl.hdel("cart%d" % user.id, *cart_selected)
        redis_cli.srem("cart_selected%d" % user.id, *cart_selected)
        redis_pl.execute()
        return order
